/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.ambimmort.ucagent.modules.server.channels;

import cn.net.greenet.db.HibernateUtil;

import cn.net.greenet.db.bean.Ackincominglog;
import cn.net.greenet.db.bean.Messageincominglog;
import cn.net.greenet.db.bean.Messageoutgoinglog;
import cn.net.greenet.db.bean.MessageoutgoinglogManual;
import com.ambimmort.ucagent.modules.server.codec.UcRawMessage;
import com.ambimmort.ucagent.modules.server.dpi.DPIEndPoint;
import com.ambimmort.ucagent.modules.server.dpi.DPIEndPointManager;
import com.ambimmort.ucagent.modules.webservice.Cacher;
import com.ambimmort.ucagent.modules.webservice.Thing;
import com.ambimmort.ucagent.utils.HexUtil;
import com.ambimmort.ucagent.utils.IdUtils;
import com.ambimmort.umessage.uc.commons.xCD;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IoSession;
import org.hibernate.Session;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.Date;

/**
 * @author 定巍
 */
public class ClientChannelHandler extends IoHandlerAdapter {

    DPIEndPoint ep = null;
    Session hibernateSession = null;

    public ClientChannelHandler() {

    }

    @Override
    public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
        if (cause instanceof IOException) {
            if (cause.getMessage().contains("Connection reset by peer")) {
                System.out.println("DPI " + session.getRemoteAddress() + " reset connection. Please Contact DPI Manufacture!");
            } else {
                cause.printStackTrace();
            }
        } else {
            cause.printStackTrace();
        }
    }

    @Override
    public void sessionOpened(IoSession session) throws Exception {
        hibernateSession = HibernateUtil.getSessionFactory().openSession();
        InetSocketAddress addr = (InetSocketAddress) session.getRemoteAddress();
        if (DPIEndPointManager.getInstance().getEndPoints().containsKey(addr.getAddress().getHostAddress())) {
            ep = DPIEndPointManager.getInstance().getEndPoints().get(addr.getAddress().getHostAddress());
            ep.getDpiEndPointBean().setIsClientChannelConnected(true);
            ep.persistence();
        }
    }

    @Override
    public void messageSent(IoSession session, Object message) throws Exception {
        if (message instanceof UcRawMessage) {
            UcRawMessage rm = (UcRawMessage) message;
            if (rm.isManaul()) {
                MessageoutgoinglogManual log = (MessageoutgoinglogManual) rm.getLog();
                log.setIsSentSuccess(true);
                Thing thing = new Thing();
                thing.setAction(Thing.UPDATE);
                thing.setData(log);
                Cacher.getInstance().addTing(thing);

            } else {
                Messageoutgoinglog log = (Messageoutgoinglog) rm.getLog();
                log.setIsSentSuccess(true);
                Thing thing = new Thing();
                thing.setAction(Thing.UPDATE);
                thing.setData(log);
                Cacher.getInstance().addTing(thing);
            }

        }
    }

    @Override
    public void messageReceived(IoSession session, Object message) throws Exception {
        if (message instanceof UcRawMessage) {
            UcRawMessage msg = (UcRawMessage) message;
            byte mt = msg.getMessageType().toByte();
            if (mt == (byte) 0xcd) {  // this is ack message
                /*
                 *  通过 UcMsg.xCD类的parse方法来解析构造UcMsg.xCD对象
                 */
                xCD ack = new xCD();
                ack.parse(msg.getHeader(), msg.getBody());

                if (ack.getMessageType().toByte() == (byte) 0x81) { //如果是AAA的ACK，则日志不记录数据库
                    //TODO:以后可以将设计改为，所有的接收消息都push到消息队列，然后根据类别记录到不同的数据库里面，AAA可以放到适合做日志的数据库中，比如HBASE，或直接定义一个log

                } else {
                    /*
                 *  构建数据库实体Bean对象UcMessageAckLogBean，并填写其
                 */
                    Ackincominglog bean = new Ackincominglog();
                    bean.setDpiendpointbean(ep.getDpiEndPointBean());
                    bean.setMessageNo(ack.getMessageNo().toInteger());
                    bean.setMessageSequenceNo(ack.getMessageSequenceNo().toLong());
                    bean.setMessageType(HexUtil.getHex(ack.getMessageType().toByte()));
                    bean.setReceiveTime(new Date(System.currentTimeMillis()));
                    bean.setAckCode(ack.getUcPacketErrorStatus().toByte());
                    bean.setAckContent(ack.getUcPacketErrorInfo().toString());
                    bean.setId(IdUtils.getId(bean)); //SVN版本128中AAA的ack报错的主要原因是Ackincominglog的hash函数没有重载。
                    /**
                     * 创建一条新的数据库记录
                     */
                    Thing thing = new Thing();
                    thing.setAction(Thing.ADD);
                    thing.setData(bean);
                    Cacher.getInstance().addTing(thing);
                    System.out.println("=uc[" + mt + "] from DPI:[" + session.getRemoteAddress() + "][log:" + bean.getId() + "]===" + msg.toString());
                }




            } else if (mt == (byte) 0xc5 || mt == (byte) 0xc6) {

                Messageincominglog log = new Messageincominglog(this.ep.getDpiEndPointBean());
                log.setFromIp(((InetSocketAddress) session.getRemoteAddress()).getAddress().getHostAddress());
                log.setMessageNo(msg.getMessageNo().toInteger());
                log.setMessageSequenceNo(msg.getMessageSequenceNo().toLong());
                log.setMessageType(HexUtil.getHex(msg.getMessageType().toByte()));
                log.setPacket(msg.getBytes());
                log.setTime(new Date(System.currentTimeMillis()));
                log.setId(IdUtils.getId(log));
                Thing thing = new Thing();
                thing.setAction(Thing.ADD);
                thing.setData(log);
                Cacher.getInstance().addTing(thing);


                System.out.println("=uc[" + mt + "] from DPI:[" + session.getRemoteAddress() + "][log:" + log.getId() + "]===" + msg.toString());

            }
        }
    }

    @Override
    public void sessionClosed(IoSession session) throws Exception {
        if (hibernateSession != null) {
            hibernateSession.close();
        }
        InetSocketAddress addr = (InetSocketAddress) session.getRemoteAddress();
        if (DPIEndPointManager.getInstance().getEndPoints().containsKey(addr.getAddress().getHostAddress())) {
            DPIEndPoint ep = DPIEndPointManager.getInstance().getEndPoints().get(addr.getAddress().getHostAddress());
            ep.getDpiEndPointBean().setIsClientChannelConnected(false);
            ep.persistence();
        }
    }

}
